using System;
using System.Collections.Generic;
using System.Text;
using GameFramework;
using GameEngine;

namespace Projet_X0
{
    public class Character : Entity
    {
        protected Position position = null;
        protected Orientation orientation = null;
        protected Speed speed = null;
        protected Collidable collidable = null;
        protected MoveFront moveFront = null;
        protected RotateLeft rotateLeft = null;
        protected RotateRight rotateRight = null;
        protected Action control = null;
        protected CheckCollision checkCollision = null;
        protected Health health = null;
        protected Update update = null;
        protected Weapons weapons = null;
        protected Fire fire = null;
        protected Energy energy = null;

        public Character(Vector2D position, float direction, int ID, Action control, float health, Weapons weapons)
            : base(ID)
        {
            this.ID = ID;
            this.position = new Position(position);
            AddState(this.position);
            this.orientation = new Orientation(direction);
            AddState(orientation);
            speed = new Speed();
            AddState(speed);
            collidable = new Collidable(this);
            AddState(collidable);
            this.health = new Health(health);
            AddState(this.health);
            this.weapons = weapons;
            if (weapons != null)
                AddState(weapons);
            energy = new Energy(1000, 1);
            AddState(energy);

            this.control = control;
            control.Activate(true);
            checkCollision = new CheckCollision(this);
            checkCollision.Activate(true);
            update = new Update(this);
            update.Activate(true);
            fire = new Fire(this);
            moveFront = new MoveFront(this);
            rotateLeft = new RotateLeft(this);
            rotateRight = new RotateRight(this);

            form = new CharacterForm(this, ID);
        }

        public void Die()
        {
            Terminate();
        }

        public Position GetPosition()
        {
            return position;
        }

        public override void Terminate()
        {
            control.Terminate();
            checkCollision.Terminate();
            fire.Terminate();
            moveFront.Terminate();
            rotateLeft.Terminate();
            rotateRight.Terminate();
            update.Terminate();

            base.Terminate();
        }

        protected class CheckCollision : Action
        {
            public CheckCollision(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Collidable collidable;
                Position position;

                collidable = ((Collidable)source.GetState((int)StatesID.Collidable)).GetCollidable();

                if (collidable.GetCollisions().Count > 0)
                {
                    position = (Position)source.GetState((int)StatesID.Position);
                    position.ResetOldPos();
                }
            }
        }

        protected class Fire : Action
        {
            public Fire(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Character character = (Character)source;
                Position pos = (Position)source.GetState((int)StatesID.Position);
                Position position = new Position(new Vector2D(pos.GetPos().GetX(), pos.GetPos().GetY()));
                float height = ((CharacterMesh)source.getForm().GetMesh()).GetHeight() / 2 + 10;
                float width = ((CharacterMesh)source.getForm().GetMesh()).GetWidth() / 2 + 10;
                Orientation orientation = (Orientation)source.GetState((int)StatesID.Orientation);
                position.Set(new Vector2D(position.GetPos().GetX() + width * (float)Math.Sin(orientation.Get()), position.GetPos().GetY() - height * (float)Math.Cos(orientation.Get())));
                Weapons weapons = (Weapons)source.GetState((int)StatesID.Weapons);
                Energy energy = (Energy)character.GetState((int)StatesID.Energy);
                if (weapons != null && (energy.Get() >= weapons.GetWeapon().GetConsomation()))
                {
                    if (weapons.GetWeapon().Fire(position, orientation))
                        energy.Decrease(weapons.GetWeapon().GetConsomation());
                    
                }
            }
        }
 
        public class Health : State
        {
            private float health = 0.0f;

            public Health(float health)
                : base((int)StatesID.Health)
            {
                this.health = health;
            }

            public void TakeDamage(float damage)
            {
                health -= damage;
                if (health < 0) health = 0.0f;
            }

            public float Get()
            {
                return health;
            }
        }

        public class Energy : State
        {

            private int energy;
            private int max;
            private int incRate;

            public Energy(int max, int incRate)
                : base((int)StatesID.Energy)
            {
                this.max = max;
                this.incRate = incRate;
                energy = max;

            }

            public void Increase()
            {
                energy += incRate;
                if (energy > max)
                    energy = max;
            }

            public int Get()
            {
                return energy;
            }

            public void Decrease(int dec)
            {
                energy -= dec;
                if (energy < 0)
                    energy = 0;
            }
        }

        protected class MoveFront : Action
        {
            public MoveFront(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Position position = (Position)source.GetState((int)StatesID.Position);
                Orientation orientation = (Orientation)source.GetState((int)StatesID.Orientation);
                Speed speed = (Speed)source.GetState((int)StatesID.Speed);
                Position pos = new Position(new Vector2D());
                pos.Set(new Vector2D((float)(position.GetPos().GetX() + Math.Sin(orientation.Get()) * speed.Get()), (float)(position.GetPos().GetY() - Math.Cos(orientation.Get()) * speed.Get())));
                if (pos.GetPos().GetX() < Display.HRES / 2)
                    pos.Set(new Vector2D(Display.HRES / 2, pos.GetPos().GetY()));
                if (pos.GetPos().GetX() > GameManager.GetServices().display.GetLimits().GetX() - Display.HRES / 2)
                    pos.Set(new Vector2D(GameManager.GetServices().display.GetLimits().GetX() - Display.HRES / 2, pos.GetPos().GetY()));
                if (pos.GetPos().GetY() < Display.VRES / 2)
                    pos.Set(new Vector2D(pos.GetPos().GetX(), Display.VRES / 2));
                if (pos.GetPos().GetY() > GameManager.GetServices().display.GetLimits().GetY() - Display.VRES / 2)
                    pos.Set(new Vector2D(pos.GetPos().GetX(), GameManager.GetServices().display.GetLimits().GetY() - Display.VRES / 2));

                position.Set(new Vector2D(pos.GetPos().GetX(), pos.GetPos().GetY()));
            }
        }

        protected class RotateLeft : Action
        {
            public RotateLeft(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Orientation orientation = (Orientation)source.GetState((int)StatesID.Orientation);
                orientation.Set(orientation.Get() - 0.02f);
            }
        }

        protected class RotateRight : Action
        {
            public RotateRight(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Orientation orientation = (Orientation)source.GetState((int)StatesID.Orientation);
                orientation.Set(orientation.Get() + 0.02f);
            }
        }

        public class Update : Action
        {
            public Update(Entity source)
                : base(source)
            {
            }

            public override void Run()
            {
                Character character = (Character)source;
                Character.Health health = (Character.Health)character.GetState((int)StatesID.Health);
                if (health != null)
                    if (health.Get() <= 0)
                    {
                        character.Die();
                    }
                ((Character.Energy)character.GetState((int)StatesID.Energy)).Increase();
            }
        }
    }
}
